package com.chendx.store.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.chendx.model.common.dtos.ResponseResult;
import com.chendx.model.common.enums.AppHttpCodeEnum;
import com.chendx.model.goods.pojo.Sku;
import com.chendx.model.goodsComment.vo.CommentCountVo;
import com.chendx.model.search.dto.SearchDto;
import com.chendx.store.search.feign.CommentFeign;
import com.chendx.store.search.feign.GoodsFeign;
import com.chendx.store.search.service.SearchService;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;

/**
 * Created by chendx on 2022/4/18.
 */
@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private RestHighLevelClient client;
    @Autowired
    private GoodsFeign goodsFeign;
    @Autowired
    private CommentFeign commentFeign;

    @Override
    public ResponseResult indexAllSearch() {
        List<Sku> skuList = goodsFeign.findAllSku();
        IndexRequest indexRequest = new IndexRequest("app_info_sku");
        for (Sku sku : skuList){
            Map<String,Object> map = new HashMap();
            map.put("name",sku.getName());
            map.put("price",sku.getPrice());
            map.put("image",sku.getImage());
            map.put("images",sku.getImages());
            map.put("createTime",sku.getCreateTime());
            map.put("spuId",sku.getSpuId());
            map.put("brandName",sku.getBrandName());
            map.put("categoryName",sku.getCategoryName());
            map.put("spec", JSON.parseObject(sku.getSpec(),Object.class));
            map.put("saleNum",sku.getSaleNum());
            map.put("commentNum",sku.getCommentNum());
            indexRequest.id(sku.getId().toString()).source(map);
            try {
                IndexResponse index = client.index(indexRequest, RequestOptions.DEFAULT);
                RestStatus restStatus = index.status();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    @Override
    public ResponseResult search(Map<String, String> searchMap) {
        if (searchMap == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        SearchRequest searchRequest = new SearchRequest("app_info_sku");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //布尔查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //关键词查询
        String keyword = "华为";
        if (!StringUtils.isEmpty(searchMap.get("name"))) {
            keyword = searchMap.get("name");
            if (keyword.contains("手机")) {
                boolQueryBuilder.must(QueryBuilders.termQuery("categoryName", "手机"));
            }
            if (keyword.contains("电视")) {
                boolQueryBuilder.must(QueryBuilders.termQuery("categoryName", "电视"));
            }
            boolQueryBuilder.must(QueryBuilders.queryStringQuery(keyword).field("name").field("brandName").defaultOperator(Operator.OR));
        }
        //分类查询
        if (!StringUtils.isEmpty(searchMap.get("categoryName"))) {
            boolQueryBuilder.must(QueryBuilders.termQuery("categoryName", searchMap.get("categoryName")));
        }
        //品牌查询
        if (!StringUtils.isEmpty(searchMap.get("brand"))) {
            boolQueryBuilder.must(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
        }
        //规格查询
        for (String key : searchMap.keySet()) {
            if (key.startsWith("spec_")) {
                if (!StringUtils.isEmpty(searchMap.get(key))){
                    boolQueryBuilder.must
                            (QueryBuilders.termsQuery("spec." + key.substring(5) + ".keyword", Arrays.asList(searchMap.get(key).split(","))));
                }
                //boolQueryBuilder.must(QueryBuilders.termQuery("specMap." + key.substring(5) + ".keyword", searchMap.get(key)));
            }
        }
        searchSourceBuilder.query(boolQueryBuilder);
        //销量排行
        if (!StringUtils.isEmpty(searchMap.get("saleNum"))) {
            searchSourceBuilder.sort("saleNum",SortOrder.valueOf(searchMap.get("saleNum")));
        }
        //价格排行
        if (!StringUtils.isEmpty(searchMap.get("priceSort"))) {
            searchSourceBuilder.sort("price",SortOrder.valueOf(searchMap.get("priceSort")));
        }
        //分页
        Integer pageNum = 1;
        Integer size = 10;
        if (!StringUtils.isEmpty(searchMap.get("pageNum"))) {
            try {
                pageNum = Integer.valueOf((String) searchMap.get("pageNum"));
            } catch (NumberFormatException e) {
                e.printStackTrace();
                pageNum = 1;
            }
        }
        searchSourceBuilder.from((pageNum-1) * size);
        searchSourceBuilder.size(10);

        //聚合分组
        // 获取商品分类的列表数据
        searchSourceBuilder.aggregation(AggregationBuilders.terms("categoryGroup").field("categoryName"));
        // 获取商品品牌的列表数据
        searchSourceBuilder.aggregation(AggregationBuilders.terms("brandGroup").field("brandName"));
        // 获取商品规格的列表数据
        //searchSourceBuilder.aggregation(AggregationBuilders.terms("specGroup").field("spec"));

        searchRequest.source(searchSourceBuilder);
        Map result = new HashMap<>();
        List<Map > list = new ArrayList<>();
        List<String> categoryList = new ArrayList<>();
        List<String> brandList = new ArrayList<>();
        try {
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            Aggregations aggregations = searchResponse.getAggregations();
            // 获取商品分类的列表数据
            Terms categoryGroup = aggregations.get("categoryGroup");
            if (categoryGroup != null && categoryGroup.getBuckets().size() > 0){
                for (Terms.Bucket entry : categoryGroup.getBuckets()){
                    String categoryName = entry.getKeyAsString();
                    categoryList.add(categoryName);
                }
            }
            // 获取商品品牌的列表数据
            Terms brandGroup = aggregations.get("brandGroup");
            if (brandGroup != null && brandGroup.getBuckets().size() > 0){
                for (Terms.Bucket entry : brandGroup.getBuckets()){
                    String brandName = entry.getKeyAsString();
                    brandList.add(brandName);
                }
            }
            SearchHits hits = searchResponse.getHits();
            for (SearchHit hit : hits){
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                String skuId = hit.getId();
                if (StringUtils.isEmpty(skuId)){
                    break;
                }
                CommentCountVo commentCountVo = loadCommentVo(skuId);

                sourceAsMap.put("id",skuId);
                String spuId = String.valueOf((long)sourceAsMap.get("spuId")) ;
                sourceAsMap.put("spuId",spuId);
                sourceAsMap.put("favorable",commentCountVo.getFavorable());
                sourceAsMap.put("commentCount",commentCountVo.getCommentCount());
                list.add(sourceAsMap);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        result.put("category",categoryList);
        result.put("brand",brandList);
        result.put("skuInfos",list);
        return ResponseResult.okResult(result);
    }

    @Override
    public ResponseResult update(SearchDto dto) {
        if(dto == null || StringUtils.isEmpty(dto.getSkuId())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        Sku sku = goodsFeign.findSkuById(Long.valueOf(dto.getSkuId()));
        if (sku == null){
            DeleteRequest deleteRequest = new DeleteRequest("app_info_sku",dto.getSkuId());
            try {
                client.delete(deleteRequest,RequestOptions.DEFAULT);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return ResponseResult.errorResult(AppHttpCodeEnum.SKU_NOT_EXIST);
        }
        UpdateRequest updateRequest = new UpdateRequest("app_info_sku",dto.getSkuId());
        if (!StringUtils.isEmpty(dto.getPrice())){
            sku.setPrice(dto.getPrice());
        }
        Map<String,Object> skuMap = JSON.parseObject(JSON.toJSONString(sku), Map.class);
        skuMap.put("spec",JSON.parseObject(sku.getSpec(),Object.class));
        updateRequest.docAsUpsert(true);
        updateRequest.doc(skuMap);

        try {
            UpdateResponse update = client.update(updateRequest, RequestOptions.DEFAULT);
            DocWriteResponse.Result result = update.getResult();
            if (result == DocWriteResponse.Result.UPDATED){
                return ResponseResult.okResult(JSON.toJSONString(skuMap));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
    }

    @Override
    public void indexSearch(String skuId) {
        Sku sku = goodsFeign.findSkuById(Long.valueOf(skuId));
        IndexRequest indexRequest = new IndexRequest("app_info_sku");
        indexRequest.id(skuId);
        Map<String,Object> map = new HashMap();
        map.put("name",sku.getName());
        map.put("price",sku.getPrice());
        map.put("image",sku.getImage());
        map.put("images",sku.getImages());
        map.put("createTime",sku.getCreateTime());
        map.put("spuId",sku.getSpuId());
        map.put("brandName",sku.getBrandName());
        map.put("categoryName",sku.getCategoryName());
        map.put("spec", JSON.parseObject(sku.getSpec(),Object.class));
        map.put("saleNum",sku.getSaleNum());
        map.put("commentNum",sku.getCommentNum());
        indexRequest.id(sku.getId().toString()).source(map);
        try {
            IndexResponse index = client.index(indexRequest, RequestOptions.DEFAULT);
            RestStatus restStatus = index.status();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    private CommentCountVo loadCommentVo(String skuId){
        CommentCountVo commentCountVo = new CommentCountVo();
        commentCountVo.setFavorable(Float.valueOf(0));
        commentCountVo.setCommentCount(Long.valueOf(0));
        try {
            commentCountVo = commentFeign.loadCommentDetail(skuId);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return  commentCountVo;
    }
}
